<?php

namespace app\service;

use think\facade\Db;
use think\facade\Log;

abstract class BaseService
{
    const STATE_ACCESS = 1; //启用
    const STATE_DENY = -1;//禁用

    public $page = 0;
    public $pageSize = 10;

    public function getPageAndSize($page = 0, $size = 0)
    {

        $this->page = $page ? $page:  request()->param("page");
        $this->pageSize = $size ? $size:request()->param("limit");
    }

    abstract protected function setModel(): string;

    /**
     * 获取模型
     * @return BaseModel
     */
    protected function getModel()
    {
        return app()->make($this->setModel(), [], true);
    }

    /**
     * 获取主键
     * @return array|string
     */
    protected function getPk()
    {
        return $this->getModel()->getPk();
    }

    /**
     * @return string
     * @author 等风来
     * @email 136327134@qq.com
     * @date 2023/2/8
     */
    public function getTableName()
    {
        return $this->getModel()->getName();
    }

    /**
     * @param $id
     * @param array|null $field
     * @param array|null $with
     * @return mixed
     * @throws
     */
    public function get($id, ?array $field = [], ?array $with = [])
    {
        if (is_array($id)) {
            $where = $id;
        } else {
            $where = [$this->getPk() => $id];
        }
        return $this->getModel()->where($where)->when(count($with), function ($query) use ($with) {
            $query->with($with);
        })->field($field ?? ['*'])->find();
    }

    /**
     * 添加或保存
     * @param $params
     * @return mixed
     */
    public function save($params)
    {
        $keys = array_keys($params);
        $model = $this->getModel();
        $fields = $this->getTableFields();
        $isUpdate = false;
        if (in_array($this->getPk(), $keys) && !empty($params[$this->getPk()])) {
            $isUpdate = true;
            $model = $model->find($params[$this->getPk()]);
            $key = array_search($this->getPk(), $keys);
            unset($keys[$key]);
        }
        foreach ($keys as $key) {
            if (in_array($key, $fields)) {
                $model->$key = $params[$key];
            }
        }
        $model->save();
        if (!$isUpdate) {
            return $model->get($this->getPk());
        }
        return $params[$this->getPk()];
    }

    public function setStatus($id, $status)
    {
        $model = $this->getModel()->where("id", $id)->find();
        if ($model->id > 0) {
            $model->status = $status;
            return $model->save();
        }
        return false;
    }

    protected function getTableFields()
    {
        return $this->getModel()->getTableFields();
    }

    public function getOne(array $where, ?string $field = '*', array $with = [])
    {
        $field = explode(',', $field);
        return $this->get($where, $field, $with);
    }

    protected function getOrder()
    {
        $order = $this->getModel()->getPk() . " desc";
        $params = request()->post();
        if (!empty($params["order"]) && !empty($params["field"])) {
            $order = sprintf("%s %s", $params["field"], $params["order"]);
        }
        return $order;
    }


    /**
     * 列表
     * @param $where
     * @param $page
     * @param $pageSize
     * @param $field
     * @return array[]
     */
    public function getList($where = [], $field = "*", array $with = [])
    {
        $this->getPageAndSize();
        $list = $this->getModel()->where($where)->field($field)->when(!empty($with), function ($query) use ($with) {
            $query->with($with);
        })->when($this->page && $this->pageSize, function ($query) {
            $query->page($this->page, $this->pageSize);
        })->order($this->getOrder())->select()->toArray();
        $total = $this->getModel()->where($where)->when(!empty($with), function ($query) use ($with) {
            $query->with($with);
        })->count();;
        return ["rows" => [
            "total" => $total,
            "list" => $list,
        ]];
    }

    /**
     * 获取单个字段值
     * @param $where
     * @param string|null $field
     * @return mixed
     */
    public function value(array $where, ?string $field = '')
    {
        $pk = $this->getPk();
        return $this->getModel()->where($where)->value($field ?: $pk);
    }

    /**
     * 获取某个字段数组
     * @param array $where
     * @param string $field
     * @param string $key
     * @return array
     */
    public function column(array $where, string $field, string $key = '')
    {
        return $this->getModel()->where($where)->column($field, $key);
    }


    /**
     * 删除
     * @param int|string|array $id
     * @return mixed
     */
    public function delete($id, ?string $key = null)
    {
        if (is_array($id)) {
            $where = $id;
        } else {
            $where = [is_null($key) ? $this->getPk() : $key => $id];
        }
        return $this->getModel()->where($where)->delete();
    }

    /**
     * 删除记录
     * @param int $id
     * @param bool $force
     * @return bool
     * @author 等风来
     * @email 136327134@qq.com
     * @date 2023/4/15
     */
    public function destroy(int $id, bool $force = false)
    {
        return $this->getModel()->destroy($id, $force);
    }

    /**
     * 更新数据
     * @param int|string|array $id
     * @param array $data
     * @param string|null $key
     * @return BaseModel
     */
    public function update($id, array $data, ?string $key = null)
    {
        if (is_array($id)) {
            $where = $id;
        } else {
            $where = [is_null($key) ? $this->getPk() : $key => $id];
        }
        return $this->getModel()::update($data, $where);
    }

    /**
     * 插入数据
     * @param array $data
     * @return mixed
     */
    public function create(array $data)
    {
        return $this->getModel()::create($data);
    }

    /**
     * 插入数据
     * @param array $data
     * @return \think\Collection
     * @throws \Exception
     */
    public function saveAll(array $data)
    {
        return $this->getModel()->saveAll($data);
    }

    /**
     * 获取所有数据
     * @param $where
     * @param $field
     * @param $order
     * @return mixed
     */
    public function getAll($where = [], $field = "*", $order = "id desc")
    {

        return $this->getModel()->where($where)->field($field)->order($order)->select();
    }

    public function clear()
    {
        return $this->getModel()->where(true)->delete();
    }

    /**
     * 数据库事务操作
     * @param callable $closure
     * @param bool $isTran
     * @return mixed
     */
    public function transaction(callable $closure, bool $isTran = true)
    {
        return $isTran ? Db::transaction($closure) : $closure();
    }


    public function getListLimit($where = [], $field = "*", $limit = 3, $order = "id desc")
    {
        return $this->getModel()->where($where)->field($field)->limit($limit)->order($order)->select();
    }

    /**
     * 求和
     * @param array $where
     * @param string $field
     * @param bool $search
     * @return float
     * @throws \ReflectionException
     */
    public function sum(array $where, string $field)
    {

        return $this->getModel()->where($where)->sum($field);

    }

    /**
     * 不需要total
     * @param $where
     * @param $field
     * @param array $with
     * @return array
     */
    public function getListLimitWith(array $where = [], string $field = "*", array $with = [],int $limit=0,string $order="id desc"): array
    {
        $this->getPageAndSize();
        $list = $this->getModel()->where($where)->field($field)->when(!empty($with), function ($query) use ($with) {
            $query->with($with);
        })->when(!empty($limit),function ($query) use($limit) {
            $query->limit($limit);
        })->order($order)->select()->toArray();
        return $list;
    }

    public function getListWithOutCount($where = [], $field = "*", array $with = [])
    {
        $this->getPageAndSize();
        $list = $this->getModel()->where($where)->field($field)->when(!empty($with), function ($query) use ($with) {
            $query->with($with);
        })->when($this->page && $this->pageSize, function ($query) {
            $query->page($this->page, $this->pageSize);
        })->order($this->getOrder())->select()->toArray();
        return $list;
    }
    /**
     * 求和
     * @param array $where
     * @param string $field
     * @param bool $search
     * @return int
     * @throws \ReflectionException
     */
    public function count(array $where, string $field="*")
    {

        return $this->getModel()->where($where)->count($field);

    }

    public function getWhereRawCount(string $query,array $params):int
    {
       return $this->getModel()->whereRaw($query,$params)->count();
    }

    public function getWhereRawList(string $query,array $params,$field="*") :array
    {
        $this->getPageAndSize();
       return  $this->getModel()->whereRaw($query,$params)->when($this->page && $this->pageSize, function ($query) {
            $query->page($this->page, $this->pageSize);
        })->order($this->getOrder())->field($field)->select()->toArray();
    }

    public function getColumn($field,$key,$where = [])
    {

        return $this->getModel()->where($where)->column($field,$key);
    }
}

